/*
 * Copyright (c) 2010 Andy Aspell-Clark
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
package uk.org.aspellclark.agenedb.gedcom.parser;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import uk.org.aspellclark.agenedb.db.DatabaseObjectContainer;
import uk.org.aspellclark.agenedb.gedcom.Gedcom;
import uk.org.aspellclark.agenedb.gedcom.model.Address;
import uk.org.aspellclark.agenedb.gedcom.model.ChangeDate;
import uk.org.aspellclark.agenedb.gedcom.model.Family;
import uk.org.aspellclark.agenedb.gedcom.model.FamilyChild;
import uk.org.aspellclark.agenedb.gedcom.model.FamilyEvent;
import uk.org.aspellclark.agenedb.gedcom.model.FamilySpouse;
import uk.org.aspellclark.agenedb.gedcom.model.Header;
import uk.org.aspellclark.agenedb.gedcom.model.HeaderSourceData;
import uk.org.aspellclark.agenedb.gedcom.model.Individual;
import uk.org.aspellclark.agenedb.gedcom.model.IndividualEvent;
import uk.org.aspellclark.agenedb.gedcom.model.IndividualEventType;
import uk.org.aspellclark.agenedb.gedcom.model.Multimedia;
import uk.org.aspellclark.agenedb.gedcom.model.Note;
import uk.org.aspellclark.agenedb.gedcom.model.PersonalName;
import uk.org.aspellclark.agenedb.gedcom.model.Repository;
import uk.org.aspellclark.agenedb.gedcom.model.Source;
import uk.org.aspellclark.agenedb.gedcom.model.SourceSystem;
import uk.org.aspellclark.agenedb.gedcom.model.Submission;
import uk.org.aspellclark.agenedb.gedcom.model.Submitter;
import uk.org.aspellclark.agenedb.gedcom.model.UserReference;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

/**
 *
 * @author andy.aspell-clark
 */
public final class GedcomParser {

	private static String GEDCOM_TAG_SUBM = "SUBM";
	private static String GEDCOM_TAG_NOTE = "NOTE";
	private static String GEDCOM_TAG_CHAN = "CHAN";
	private static String GEDCOM_TAG_SOUR = "SOUR";
	private static String GEDCOM_TAG_RIN = "RIN";
	private static String GEDCOM_TAG_TYPE = "TYPE";
	private static String GEDCOM_TAG_REFN = "REFN";

	private static GedcomParser instance;

	private static String LOG_TAG = "GedcomParser";

	public static GedcomParser getParser() {
		if (GedcomParser.instance == null) {
			GedcomParser.instance = new GedcomParser();
		}
		return GedcomParser.instance;
	}

	/**
	 * The content of the gedcom file.
	 */
	public Gedcom gedcom = Gedcom.getInstance();

	/**
	 * The things that went wrong while parsing the gedcom file.
	 */
	public List<String> errors = new ArrayList<String>();

	/**
	 * The warnings issued during the parsing of the gedcom file.
	 */
	public List<String> warnings = new ArrayList<String>();
	private FileReader gedcomFileRdr;
	private BufferedReader bufferedReader = null;
	private StringBuffer currLineRead = new StringBuffer(256);
	private int currBytesRead;
	private int currParsingProgress;
	private Message hndlrMsg;
	private Handler progressHandler;

	private String filename;

	private GedcomParser() {
	}

	private void fileClose() {
		try {
			this.bufferedReader.close();
			this.gedcomFileRdr.close();
		} catch (Exception e) {
			Log.e(LOG_TAG, e.getMessage());
		}
	}

	private void fileOpen() throws FileNotFoundException {
		File gedcomFile = new File(this.filename);
		this.gedcomFileRdr = new FileReader(gedcomFile);
		this.bufferedReader = new BufferedReader(this.gedcomFileRdr, 16384);
	}

	private void fileReadFirstLine() {
		try {
			this.currLineRead.delete(0, this.currLineRead.length());
			this.currLineRead.append(this.bufferedReader.readLine().trim());
			this.currBytesRead = this.currLineRead.length();
		} catch (IOException e) {
			this.currLineRead.delete(0, this.currLineRead.length());
		}
	}

	private void fileReadNextLine() {
		try {
			this.currLineRead.delete(0, this.currLineRead.length());
			this.currLineRead.append(this.bufferedReader.readLine());

			this.progressHandler.removeMessages(this.currBytesRead);
			if (this.currLineRead != null) {
				this.currBytesRead += this.currLineRead.length();
			}
		} catch (Throwable e) {
			Log.e(LOG_TAG, e.getMessage());
			this.errors.add("Error parsing Gedcom file [" + e.getMessage() + "]");
			this.currLineRead.delete(0, this.currLineRead.length());
		}
	}

	/**
	 * Get a family by their xref, adding them to the gedcom collection of
	 * families if needed.
	 *
	 * @param xref
	 *          the xref of the family
	 * @return the family with the specified xref
	 */
	private Family getFamily(String xref) {
		Family f = DatabaseObjectContainer.familyCntrlr.getFamily(xref);
		if (f == null) {
			f = new Family();
			f.xref = xref;
			DatabaseObjectContainer.familyCntrlr.addFamily(f);
		}
		return f;
	}

	private String getIdFromString(CharSequence cs) {
		StringBuffer retStr = new StringBuffer();

		for (int x = 0; x < cs.length(); x++) {
			char ch = cs.charAt(x);
			if (ch == '@') {
				retStr.append(ch);
				x++;
				ch = cs.charAt(x);
				while (ch != '@') {
					retStr.append(ch);
					x++;
					ch = cs.charAt(x);
				}
				retStr.append(ch);
				break;
			}
		}
		return retStr.toString();
	}

	/**
	 * Get an individual by their xref, adding them to the gedcom collection of
	 * individuals if needed.
	 *
	 * @param xref
	 *          the xref of the individual
	 * @return the individual with the specified xref
	 */
	private Individual getIndividual(String xref) {
		Individual i;
		i = DatabaseObjectContainer.individualCntrlr.getIndividual(xref);
		if (i == null) {
			i = new Individual();
			i.xref = xref;
			DatabaseObjectContainer.individualCntrlr.addIndividual(i);
		}
		return i;
	}

	private int getLevelNum(StringBuffer txtLine) {
		return Integer.parseInt(txtLine.substring(0, 1));
	}

	/**
	 * Get a multimedia item by its xref, adding it to the gedcom collection of
	 * multimedia items if needed.
	 *
	 * @param xref
	 *          the xref of the multimedia item
	 * @return the multimedia item with the specified xref
	 */
	private Multimedia getMultimedia(String xref) {
		Multimedia m;
		m = DatabaseObjectContainer.multimediaCntrlr.getMultimediaRecord(xref);
		if (m == null) {
			m = new Multimedia();
			m.xref = xref;
			DatabaseObjectContainer.multimediaCntrlr.addMultimedia(m);
		}
		return m;
	}

	/**
	 * Get a note by its xref, adding it to the gedcom collection of notes if
	 * needed.
	 *
	 * @param xref
	 *          the xref of the note
	 * @return the note with the specified xref
	 */
	private Note getNote(String xref) {
		Note note;
		note = DatabaseObjectContainer.noteCntrlr.getNoteRecord(xref);
		if (note == null) {
			note = new Note();
			note.xref = xref;
			DatabaseObjectContainer.noteCntrlr.addNote(note);
		}
		return note;
	}

	/**
	 * Get a repository by its xref, adding it to the gedcom collection of
	 * repositories if needed.
	 *
	 * @param xref
	 *          the xref of the repository
	 * @return the repository with the specified xref
	 */
	private Repository getRepository(String xref) {
		Repository r = DatabaseObjectContainer.repositoryCntrlr.getRepository(xref);
		if (r == null) {
			r = new Repository();
			r.xref = xref;
			DatabaseObjectContainer.repositoryCntrlr.addRepository(r);
		}
		return r;

	}

	/**
	 * Get a source by its xref, adding it to the gedcom collection of sources if
	 * needed.
	 *
	 * @param xref
	 *          the xref of the source
	 * @return the source with the specified xref
	 */
	private Source getSource(String xref) {
		Source src = DatabaseObjectContainer.sourceCntrlr.getSource(xref);
		if (src == null) {
			src = new Source();
			src.xref = xref;
			DatabaseObjectContainer.sourceCntrlr.addSource(src);
		}
		return src;
	}

	/**
	 * Get a submitter by their xref, adding them to the gedcom collection of
	 * submitters if needed.
	 *
	 * @param xref
	 *          the xref of the submitter
	 * @return the submitter with the specified xref
	 */
	private Submitter getSubmitter(String xref) {
		Submitter i = DatabaseObjectContainer.submitterCntrlr.getSubmitter(xref);
		if (i == null) {
			i = new Submitter();
			i.xref = xref;
			DatabaseObjectContainer.submitterCntrlr.addSubmitter(i);
		}
		return i;
	}

	private Address importAddressStructure(int currentLevelNumber) {

		Address addr = new Address();
		StringBuffer addressDetails = new StringBuffer();
		if (this.currLineRead.length() > 7) {
			addressDetails.append(this.currLineRead.substring(7, this.currLineRead.length())); //get data after '0 ADDR' which are tokens 0 and 1
		}

		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			//Here we handle the different fields from the Address Structure
			if (this.currLineRead.indexOf("CONT") > 0) {
				//We now have a CONTinuation line, so we append it to the end of the address
				addressDetails.append(", ");
				if (this.currLineRead.length() > 7) {
					addressDetails.append(this.currLineRead.substring(7, this.currLineRead.length())); //get data after '2 CONT' which are tokens 0 and 1
				}
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ADR1") > 0) {
				addressDetails.append(", ");
				if (this.currLineRead.length() > 7) {
					addressDetails.append(this.currLineRead.substring(7, this.currLineRead.length())); //get data after '2 CONT' which are tokens 0 and 1
				}
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ADR2") > 0) {
				addr.addr2 = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("CITY") > 0) {
				addr.city = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("STAE") > 0) {
				addr.stateProvince = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("POST") > 0) {
				addr.postalCode = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("CTRY") > 0) {
				addr.country = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		addr.addr1 = addressDetails.toString();

		return addr;

	}

	private ChangeDate importChangeDate(int currentLevelNumber) {
		ChangeDate tmpObj = new ChangeDate();
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			if (this.currLineRead.indexOf("DATE") > 0) {
				tmpObj.date = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("TIME") > 0) {
				tmpObj.time = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_NOTE) > 0) {
				tmpObj.notes.add(this.importNoteRecord(this.getLevelNum(this.currLineRead)));
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		return tmpObj;
	}

	private FamilyEvent importFamilyEvent(int currentLevelNumber) {

		FamilyEvent tmpObj = new FamilyEvent();
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			if (this.currLineRead.indexOf("HUSB") > 0) {
				this.fileReadNextLine();
				tmpObj.husbandAge = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("WIFE") > 0) {
				this.fileReadNextLine();
				tmpObj.wifeAge = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("DATE") > 0) {
				tmpObj.date = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("TYPE") > 0) {
				tmpObj.type = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("CAUS") > 0) {
				tmpObj.cause = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("RELI") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("RESN") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("PLAC") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("AGNC") > 0) {
				tmpObj.respAgency = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_NOTE) > 0) {
				tmpObj.notes.add(this.importNoteRecord(this.getLevelNum(this.currLineRead)));
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		return tmpObj;
	}

	private void importFamilyRecord(int currentLevelNumber) {
		//create a new family in the data model
		Family famly = this.getFamily(this.getIdFromString(this.currLineRead));
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			} else if (this.currLineRead.indexOf("RESN") > 0) {
				famly.restrictionNotice = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if ((this.currLineRead.indexOf("ANUL") > 0) || (this.currLineRead.indexOf("CENS") > 0)
					|| (this.currLineRead.indexOf("DIV") > 0) || (this.currLineRead.indexOf("DIVF") > 0)
					|| (this.currLineRead.indexOf("ENGA") > 0) || (this.currLineRead.indexOf("MARR") > 0)
					|| (this.currLineRead.indexOf("MARB") > 0) || (this.currLineRead.indexOf("MARC") > 0)
					|| (this.currLineRead.indexOf("MARL") > 0) || (this.currLineRead.indexOf("MARS") > 0)
					|| (this.currLineRead.indexOf("EVEN") > 0) || (this.currLineRead.indexOf("SLGS") > 0)) {
				FamilyEvent tmpEvent = this.importFamilyEvent(this.getLevelNum(this.currLineRead));
				famly.events.add(tmpEvent);
			} else if (this.currLineRead.indexOf("HUSB") > 0) {
				famly.husband = this.getIdFromString(this.currLineRead);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("WIFE") > 0) {
				famly.wife = this.getIdFromString(this.currLineRead);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("CHIL") > 0) {
				famly.children.add(this.getIdFromString(this.currLineRead));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("NCHI") > 0) {
				famly.numChildren = Integer.parseInt(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_SUBM) > 0) {
				famly.submitters.add(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("REFN") > 0) {
				UserReference ur = new UserReference();
				ur.referenceNum = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
				if (this.currLineRead.indexOf("TYPE") > 0) {
					ur.type = this.currLineRead.substring(7, this.currLineRead.length());
				}
				famly.userReferences.add(ur);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("RIN") > 0) {
				famly.recIdNumber = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_CHAN) > 0) {
				famly.changeDate = this.importChangeDate(this.getLevelNum(this.currLineRead));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_NOTE) > 0) {
				Note nte = this.importNoteRecord(this.getLevelNum(this.currLineRead));
				famly.notes.add(nte);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_SOUR) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("OBJE") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		DatabaseObjectContainer.familyCntrlr.addFamily(famly);
	}

	private void importHeaderRecord(int currentLevelNumber) {
		this.fileReadNextLine();
		Header hdr = new Header();

		//Loop while there are no errors reading in from the file
		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}

			if (this.currLineRead.indexOf(GEDCOM_TAG_SOUR) > 0) {
				hdr.sourceSystem = this.importHeaderSourceSystem(this.getLevelNum(this.currLineRead));
			} else if (this.currLineRead.indexOf("NAME") > 0) {
				hdr.copyrightData += " " + this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("DEST") > 0) {
				hdr.destinationSystem = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("DATE") > 0) {
				StringBuffer sb = new StringBuffer(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
				if (this.currLineRead.indexOf("TIME") > 0) {
					sb.append(" : ").append(this.currLineRead.substring(7, this.currLineRead.length()));
					this.fileReadNextLine();
				}
				hdr.date = sb.toString();
			} else if (this.currLineRead.indexOf("SUBN") > 0) {
				hdr.submission = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_SUBM) > 0) {
				hdr.submitter = this.getSubmitter(this.getIdFromString(this.currLineRead));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("GEDC") > 0) {
				this.fileReadNextLine();
				if (this.currLineRead.indexOf("VERS") > 0) {
					hdr.gedcomVersion.versionNumber = this.currLineRead.substring(7, this.currLineRead.length());
					this.fileReadNextLine();
					if (this.currLineRead.indexOf("FORM") > 0) {
						hdr.gedcomVersion.gedcomForm = this.currLineRead.substring(7, this.currLineRead.length());
						this.fileReadNextLine();
					}
				}
			} else if (this.currLineRead.indexOf("CHAR") > 0) {
				hdr.characterSet.characterSetName = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("COPR") > 0) {
				hdr.copyrightData += "\n" + this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("LANG") > 0) {
				hdr.language = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("PLAC") > 0) {
				StringBuffer sb = new StringBuffer(this.getIdFromString(this.currLineRead));
				this.fileReadNextLine();
				if (this.currLineRead.indexOf("FORM") > 0) {
					sb.append(" : ").append(this.currLineRead.substring(7, this.currLineRead.length()));
					this.fileReadNextLine();
				} else {
				}
				hdr.placeStructure = sb.toString();
			} else if (this.currLineRead.indexOf("FILE") > 0) {
				hdr.fileName = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_NOTE) > 0) {
				hdr.notes.add(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
				while (this.currLineRead.indexOf("CONC") > 0 || this.currLineRead.indexOf("CONT") > 0) {
					hdr.notes.add(this.currLineRead.substring(7, this.currLineRead.length()));
					this.fileReadNextLine();
				}
			} else {
				this.fileReadNextLine();
			}
		}
		DatabaseObjectContainer.headerCntrlr.addHeader(hdr);
	}

	private HeaderSourceData importHeaderSourceData(int currentLevelNumber) {
		HeaderSourceData pn = new HeaderSourceData();

		pn.name = this.currLineRead.substring(7, this.currLineRead.length());

		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			if (this.currLineRead.indexOf("DATE") > 0) {
				pn.publishDate = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("COPR") > 0) {
				StringBuffer sb = new StringBuffer(this.currLineRead.substring(7, this.currLineRead.length()));
				this.fileReadNextLine();
				while (this.currLineRead.indexOf("CONC") > 0 || this.currLineRead.indexOf("CONT") > 0) {
					sb.append(" ").append(this.currLineRead.substring(7, this.currLineRead.length()));
				}
				pn.copyright = sb.toString();
			} else {
				this.fileReadNextLine();
			}
		}
		return pn;
	}

	private SourceSystem importHeaderSourceSystem(int currentLevelNumber) {
		SourceSystem pn = new SourceSystem();

		pn.systemId = this.currLineRead.substring(7, this.currLineRead.length());

		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			if (this.currLineRead.indexOf("VERS") > 0) {
				pn.versionNum = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("NAME") > 0) {
				pn.productName = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("CORP") > 0) {
				pn.corporation.businessName = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
				pn.corporation.address = this.importAddressStructure(this.getLevelNum(this.currLineRead));
			} else if (this.currLineRead.indexOf("DATA") > 0) {
				pn.sourceData = this.importHeaderSourceData(this.getLevelNum(this.currLineRead));
			}
			this.fileReadNextLine();
		}
		return pn;
	}

	private IndividualEvent importIndividualEvent(int currentLevelNumber) {
		IndividualEvent tmpObj = new IndividualEvent();

		if (this.currLineRead.length() > 6) {
			tmpObj.type = this.currLineRead.substring(1, 6).trim();
			//tmpObj.description = this.currLineRead.substring(7, this.currLineRead.length());
		}
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}

			if (this.currLineRead.indexOf("AGE") > 0) {
				tmpObj.age = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("DATE") > 0) {
				tmpObj.date = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("CAUS") > 0) {
				tmpObj.cause = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("RELI") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("RESN") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("AGNC") > 0) {
				tmpObj.respAgency = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_NOTE) > 0) {
				tmpObj.notes.add(this.importNoteRecord(this.getLevelNum(this.currLineRead)));
			} else {
				this.fileReadNextLine();
			}
		}
		return tmpObj;
	}

	private FamilyChild importIndividualFamilyChild(int currentLevelNumber) {
		FamilyChild pn = new FamilyChild();

		pn.family = this.getFamily(this.getIdFromString(this.currLineRead));
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			if (this.currLineRead.indexOf(GEDCOM_TAG_NOTE) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("PEDI") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ADOP") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		return pn;
	}

	private FamilySpouse importIndividualFamilySpouse(int currentLevelNumber) {
		FamilySpouse pn = new FamilySpouse();

		pn.family = this.getFamily(this.getIdFromString(this.currLineRead));
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			if (this.currLineRead.indexOf(GEDCOM_TAG_NOTE) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("PEDI") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ADOP") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		return pn;
	}

	/**
	 * Import a personal name structure for an individual.
	 *
	 * <table border=1><tr><td colspan=6>PERSONAL_NAME_STRUCTURE:=</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;<b>n</b>&nbsp;</td><td colspan=3>NAME &lt;NAME_PERSONAL></td><td>{1:1}</td><td>p.54</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>+1</td><td colspan=2>TYPE &lt;NAME_TYPE></td><td>{0:1}</td><td>p.56</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>+1</td><td colspan=2>&lt;&lt;PERSONAL_NAME_PIECES>></td><td>{0:1}</td><td>p.37</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>+1</td><td colspan=2>FONE &lt;NAME_PHONETIC_VARIATION></td><td>{0:M}</td><td>p.55</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>+2</td><td>TYPE &lt;PHONETIC_TYPE></td><td>{1:1}</td><td>p.57</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>+2</td><td>&lt;&lt;PERSONAL_NAME_PIECES>></td><td>{0:1}</td><td>p.37</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>+1</td><td colspan=2>ROMN &lt;NAME_ROMANIZED_VARIATION></td><td>{0:M}</td><td>p.56</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>+2</td><td>TYPE &lt;ROMANIZED_TYPE></td><td>{1:1}</td><td>p.61</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>+2</td><td>&lt;&lt;PERSONAL_NAME_PIECES>></td><td>{0:1}</td><td>p.37</td></tr>
	 * </table>
	 * <p>
	 * The name value is formed in the manner the name is normally spoken, with
	 * the given name and family name (surname) separated by slashes (/).
	 * (See &lt;NAME_PERSONAL>, page 54.) Based on the dynamic nature or unknown
	 * compositions of naming conventions, it is difficult to provide more
	 * detailed name piece structure to handle every case. The NPFX, GIVN, NICK,
	 * SPFX, SURN, and NSFX tags are provided optionally for systems that cannot
	 * operate effectively with less structured information. For current future
	 * compatibility, all systems must construct their names based on the
	 * &lt;NAME_PERSONAL> structure. Those using the optional name pieces should
	 * assume that few systems will process them, and most will not provide
	 * the name pieces.
	 * </p><p>
	 * A &lt;NAME_TYPE> is used to specify the particular variation that this name
	 * is. For example; if the name type is subordinate to the &lt;NAME_PERSONAL>
	 * it could indicate that this name is a name taken at immigration or that
	 * it could be an ‘also known as’ name (see page 56.)
	 * </p><p>
	 * Future GEDCOM releases (6.0 or later) will likely apply a very different
	 * strategy to resolve this problem, possibly using a sophisticated parser
	 * and a name-knowledge database.
	 * </p>
	 *
	 * @param acurrLineRead the first line of the record
	 * @param currentLevelNumber the record level number for this record
	 * @return a PersonalName structure
	 */
	private PersonalName importIndividualPersonalName(int currentLevelNumber) {
		PersonalName pn = new PersonalName();
		pn.basic = this.currLineRead.substring(7, this.currLineRead.length());

		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}

			if (this.currLineRead.indexOf("NPFX") > 0) {
				pn.prefix = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("GIVN") > 0) {
				if (this.currLineRead.length() > 7) {
					pn.givenName = this.currLineRead.substring(7, this.currLineRead.length());
				}
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("NICK") > 0) {
				if (this.currLineRead.length() > 7) {
					pn.nickname = this.currLineRead.substring(7, this.currLineRead.length());
				}
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("SPFX") > 0) {
				if (this.currLineRead.length() > 7) {
					pn.surnamePrefix = this.currLineRead.substring(7, this.currLineRead.length());
				}
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("SURN") > 0) {
				pn.surname = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("NSFX") > 0) {
				if (this.currLineRead.length() > 7) {
					pn.suffix = this.currLineRead.substring(7, this.currLineRead.length());
				}
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_SOUR) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_NOTE) > 0) {
				pn.notes.add(this.importNoteRecord(this.getLevelNum(this.currLineRead)));
			} else {
				this.fileReadNextLine();
			}
		}
		return pn;
	}

	/**
	 * read in an individual record and add it to the gedcom store.
	 * @param acurrLineRead the first line of the record
	 * @param currentLevelNumber the record level number for this record
	 * @return the individual record read in from the file
	 */
	private void importIndividualRecord(int currentLevelNumber) {
		Individual ind = this.getIndividual(this.currLineRead.substring(2, this.currLineRead.length() - 5));

		this.fileReadNextLine();
		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			} else if (this.currLineRead.indexOf("NAME") > 0) {
				PersonalName pn = this.importIndividualPersonalName(this.getLevelNum(this.currLineRead));
				ind.names.add(pn);
			} else if (this.currLineRead.indexOf("RESN") > 0) {
				ind.restrictionNotice = this.currLineRead.substring(7, this.currLineRead.length() - 1);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("SEX") > 0) {
				ind.sex = this.currLineRead.substring(this.currLineRead.length() - 1, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (IndividualEventType.isValidTag(this.currLineRead.substring(2, this.currLineRead.length()).trim())) {
				ind.events.add(this.importIndividualEvent(this.getLevelNum(this.currLineRead)));
			} else if (this.currLineRead.indexOf("FAMC") > 0) {
				FamilyChild fc = this.importIndividualFamilyChild(this.getLevelNum(this.currLineRead));
				ind.familiesWhereChild.add(fc);
			} else if (this.currLineRead.indexOf("FAMS") > 0) {
				FamilySpouse fs = this.importIndividualFamilySpouse(this.getLevelNum(this.currLineRead));
				ind.familiesWhereSpouse.add(fs);
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_SUBM) > 0) {
				ind.submitters.add(this.currLineRead.substring(7, this.currLineRead.length() - 1));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ASSO") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ALIA") > 0) {
				ind.aliases.add(this.currLineRead.substring(7, this.currLineRead.length() - 1));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ANCI") > 0) {
				ind.ancestorInterest.add(this.currLineRead.substring(7, this.currLineRead.length() - 1));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("DESI") > 0) {
				ind.descendantInterest.add(this.currLineRead.substring(7, this.currLineRead.length() - 1));
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_SOUR) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("OBJE") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_NOTE) > 0) {
				ind.notes.add(this.importNoteRecord(this.getLevelNum(this.currLineRead)));
			} else if (this.currLineRead.indexOf("RFN") > 0) {
				ind.regFileNumber = this.currLineRead.substring(7, this.currLineRead.length() - 1);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("AFN") > 0) {
				ind.ancestralFileNumber = this.currLineRead.substring(7, this.currLineRead.length() - 1);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_REFN) > 0) {
				UserReference ur = new UserReference();
				ur.referenceNum = this.currLineRead.substring(7, this.currLineRead.length() - 1);
				this.fileReadNextLine();
				if (this.currLineRead.indexOf(GEDCOM_TAG_TYPE) > 0) {
					ur.type = this.currLineRead.substring(7, this.currLineRead.length() - 1);
					this.fileReadNextLine();
				}
				ind.userReferences.add(ur);
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_RIN) > 0) {
				ind.recIdNumber = this.currLineRead.substring(7, this.currLineRead.length() - 1);
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_CHAN) > 0) {
				ind.changeDate = this.importChangeDate(this.getLevelNum(this.currLineRead));
			} else {
				this.fileReadNextLine();
			}
		}
		DatabaseObjectContainer.individualCntrlr.addIndividual(ind);
	}

	/**
	 * Import a multimedia structure.
	 *
	 * @param acurrLineRead the first line of the record
	 * @param currentLevelNumber the record level number for this record
	 * @return a multimedia record
	 */
	private void importMultimediaRecord(int currentLevelNumber) {
		Multimedia tmpObj = this.getMultimedia(this.getIdFromString(this.currLineRead));
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}

			//FIXME : Finish import
			this.fileReadNextLine();
		}

		if (tmpObj != null) {
			DatabaseObjectContainer.multimediaCntrlr.addMultimedia(tmpObj);
		}
	}

	/**
	 * Import a note record.
	 *
	 * <table border=1><tr><td colspan=7>NOTE_RECORD:=</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;<b>n</b>&nbsp;</td><td colspan=3>@&lt;XREF:NOTE>@</td><td>NOTE</td><td>&lt;SUBMITTER_TEXT></td><td>{1:1}</td><td>p.63</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>+1</td><td></td><td>[CONC|CONT]</td><td colspan=2>&lt;SUBMITTER_TEXT></td><td>{0:M}</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>+1</td><td></td><td>REFN</td><td colspan=2>&lt;USER_REFERENCE_NUMBER></td><td>{0:M}</td><td>p.63, 64</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>+2</td><td>TYPE</td><td colspan=2>&lt;USER_REFERENCE_TYPE></td><td>{0:1}</td><td>p.64</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>+1</td><td></td><td>RIN</td><td colspan=2>&lt;AUTOMATED_RECORD_ID></td><td>{0:1}</td><td>p.43</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>+1</td><td></td><td colspan=3>&lt;&lt;SOURCE_CITATION>></td><td>{0:M}</td><td>p.39</td></tr>
	 * <tr><td>&nbsp;</td><td>&nbsp;</td><td>+1</td><td></td><td colspan=3>&lt;&lt;CHANGE_DATE>></td><td>{0:1}</td><td>p.31</td></tr>
	 * </table>
	 *
	 * @param acurrLineRead the first line of the record
	 * @param currentLevelNumber the record level number for this record
	 * @return a Note Record
	 */
	private Note importNoteRecord(int currentLevelNumber) {
		Note tmpObj = this.getNote(this.getIdFromString(this.currLineRead));
		if (this.currLineRead.length() > 6) {
			tmpObj.lines.add(this.currLineRead.substring(7, this.currLineRead.length()));
		}

		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}

			if ((this.currLineRead.indexOf("CONC") > 0) || (this.currLineRead.indexOf("CONT") > 0)) {
				if (this.currLineRead.length() > 6) {
					tmpObj.lines.add(new StringBuffer(" ")
							.append(this.currLineRead.substring(7, this.currLineRead.length())).toString());
				}
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("REFN") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("RIN") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_SOUR) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_CHAN) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		if (tmpObj != null) {
			DatabaseObjectContainer.noteCntrlr.addNote(tmpObj);
		}
		return tmpObj;
	}

	private void importRepositoryRecord(int currentLevelNumber) {
		Repository rpos = this.getRepository(this.getIdFromString(this.currLineRead));
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			}
			//Here we handle the different fields from the Header record
			if (this.currLineRead.indexOf(GEDCOM_TAG_SUBM) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("FAMF") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		DatabaseObjectContainer.repositoryCntrlr.addRepository(rpos);
	}

	private void importSourcePrimitive(int currentLevelNumber) {
		Source sour = this.getSource(this.getIdFromString(this.currLineRead));
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_SUBM) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("FAMF") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		if (sour != null) {
			DatabaseObjectContainer.srcPrimitveCntrlr.addSourcePrimitive(sour);
		}
	}

	private void importSubmissionRecord(int currentLevelNumber) {
		Submission subm = null;
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_SUBM) > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("FAMF") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else {
				this.fileReadNextLine();
			}
		}
		DatabaseObjectContainer.submissionCntrlr.addSubmission(subm);
	}

	private void importSubmitterRecord(int currentLevelNumber) {
		Submitter subm = this.getSubmitter(this.getIdFromString(this.currLineRead));
		this.fileReadNextLine();

		while (this.currLineRead != null && this.currLineRead.length() > 0) {
			if (this.getLevelNum(this.currLineRead) <= currentLevelNumber) {
				break;
			} else if (this.currLineRead.indexOf("NAME") > 0) {
				subm.name = this.currLineRead.substring(7, this.currLineRead.length());
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("ADDR") > 0) {
				subm.address = this.importAddressStructure(this.getLevelNum(this.currLineRead));
			} else if (this.currLineRead.indexOf("PHON") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("LANG") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("RFN") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf("RIN") > 0) {
				//FIXME : Finish import
				this.fileReadNextLine();
			} else if (this.currLineRead.indexOf(GEDCOM_TAG_CHAN) > 0) {
				this.importChangeDate(this.getLevelNum(this.currLineRead));
			} else {
				this.fileReadNextLine();
			}
		}
		DatabaseObjectContainer.submitterCntrlr.addSubmitter(subm);
	}

	/**
	 * opens the gedcom file, reads it's contents in and parses them into
	 * the gedcom data model.
	 * @param progressHandler 
	 */
	public void parse(Handler progressHndlr) {
		// start tracing to "/sdcard/GedcomParse.trace"
		//Debug.startMethodTracing("GedcomParse");

		this.errors = new ArrayList<String>();
		this.warnings = new ArrayList<String>();

		this.currBytesRead = 0;
		this.progressHandler = progressHndlr;
		this.hndlrMsg = this.progressHandler.obtainMessage(this.currBytesRead);

		try {
			//if ( !mergeNewDataIntoCurrent )
			{
				DatabaseObjectContainer.dbCntrlr.closeDatabase();
				DatabaseObjectContainer.dbCntrlr.deleteDatabase();
				DatabaseObjectContainer.dbCntrlr.openDatabase();
			}
			this.fileOpen();
			this.fileReadFirstLine();

			//if first line of file isn't "0 HEAD" then the file is not in GedCom format
			if (this.currLineRead.length() == 0 || !(this.currLineRead.indexOf("0 HEAD") == 0)) {
				//File is too short to be a Gedcom File
				this.fileClose();
				return;
			}
			int currentLevelNumber = 0;
			while (this.currLineRead != null && this.currLineRead.length() > 0) {
				this.updateProgressHandler();
				try {
					//each of the following routines handles a single record type
					//We expect the routine to read in the first line of the Next
					//record (that is each record handler will read in the first line
					//of the record that follows it).
					if (this.currLineRead.indexOf("0") == 0) {
						if (this.currLineRead.indexOf("0 HEAD") == 0) {
							this.importHeaderRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 SUBN") == 0) {
							this.importSubmissionRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("INDI") == (this.currLineRead.length() - 4)) {
							this.importIndividualRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("FAM") == (this.currLineRead.length() - 3)) {
							this.importFamilyRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 OBJE") == 0) {
							this.importMultimediaRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 NOTE") == 0) {
							this.importNoteRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 REPO") == 0) {
							this.importRepositoryRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 SOUR") == 0) {
							this.importSourcePrimitive(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 SUBM") == 0) {
							this.importSubmitterRecord(currentLevelNumber);
						} else if (this.currLineRead.indexOf("0 TRLR") == 0) {
							//the "0 TRLR" record just tells us that we have reached the end
							//of the file, so we 'break' out of the while loop
							break;
						} else {
							this.fileReadNextLine();
						}
					} else {
						this.warnings.add("unknown tag found [" + this.currLineRead + "]");
						this.fileReadNextLine();
					}
				} catch (Exception e) {
					this.errors.add("Error parsing Gedcom file [" + e.getMessage() + "]");
					this.fileReadNextLine();
				}
			}
		} catch (Exception e) {
			this.errors.add("Error parsing Gedcom file [" + e.getMessage() + "]");
		}

		this.fileClose();
		// stop tracing
		//Debug.stopMethodTracing();
	}

	/**
	 * sets the filename to read the gedcom data from.
	 * @param value the gedcom file name.
	 */
	public void setGedcomFilename(String value) {
		this.filename = value;
	}

	private void updateProgressHandler() {
		this.progressHandler.removeMessages(this.currParsingProgress);
		this.currParsingProgress = this.currBytesRead;
		this.hndlrMsg = this.progressHandler.obtainMessage(this.currParsingProgress);
		this.progressHandler.sendMessage(this.hndlrMsg);
		//System.gc();
	}
}
